Trò chơi Angry Birds trong UNITY Engine
31.679 lượt xem;
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 public class Go : MonoBehaviour
7 {
8 // defaults used for all tweens/properties that are not explicitly set
9 public static GoEaseType defaultEaseType = GoEaseType.Linear;
10 public static GoLoopType defaultLoopType = GoLoopType.RestartFromBeginning;
11 public static GoUpdateType defaultUpdateType = GoUpdateType.Update;
12
13 // defines what we should do in the event that a TweenProperty is added and an already existing tween has the same
14 // property and target
15 public static GoDuplicatePropertyRuleType duplicatePropertyRule = GoDuplicatePropertyRuleType.None;
16 public static GoLogLevel logLevel = GoLogLevel.Warn;
17
18 // validates that the target object still exists each tick of the tween. NOTE: it is recommended
19 // that you just properly remove your tweens before destroying any objects even though this might destroy them for you
20 public static bool validateTargetObjectsEachTick = true;
21
22 // Used to stop instances being created while the application is quitting
23 private static bool _applicationIsQuitting = false;
24
25 private static List<AbstractGoTween> _tweens = new List<AbstractGoTween>(); // contains Tweens, TweenChains and TweenFlows
26 private bool _timeScaleIndependentUpdateIsRunning;
27
28 // only one Go can exist
29 static Go _instance = null;
30 public static Go instance
31 {
32 get
33 {
34 // Don't allow new instances to be created when the application is quitting to avoid the GOKit object never being destroyed.
35 // These dangling instances can't be found with FindObjectOfType and so you'd get multiple instances in a scene.
36 if( !_instance && !_applicationIsQuitting )
37 {
38 // check if there is a GO instance already available in the scene graph
39 _instance = FindObjectOfType( typeof( Go ) ) as Go;
40
41 // possible Unity bug with FindObjectOfType workaround
42 //_instance = FindObjectOfType( typeof( Go ) ) ?? GameObject.Find( "GoKit" ).GetComponent<Go>() as Go;
43
44 // nope, create a new one
45 if( !_instance )
46 {
47 var obj = new GameObject( "GoKit" );
48 _instance = obj.AddComponent<Go>();
49 DontDestroyOnLoad( obj );
50 }
51 }
52
53 return _instance;
54 }
55 }
56
57
58 /// <summary>
59 /// loops through all the Tweens and updates any that are of updateType. If any Tweens are complete
60 /// (the update call will return true) they are removed.
61 /// </summary>
62 private void handleUpdateOfType( GoUpdateType updateType, float deltaTime )
63 {
64 // loop backwards so we can remove completed tweens
65 for( var i = _tweens.Count - 1; i >= 0; --i )
66 {
67 var t = _tweens[i];
68
69 if( t.state == GoTweenState.Destroyed )
70 {
71 // destroy method has been called
72 removeTween( t );
73 }
74 else
75 {
76 // only process tweens with our update type that are running
77 if( t.updateType == updateType && t.state == GoTweenState.Running && t.update( deltaTime * t.timeScale ) )
78 {
79 // tween is complete if we get here. if destroyed or set to auto remove kill it
80 if( t.state == GoTweenState.Destroyed || t.autoRemoveOnComplete )
81 {
82 removeTween( t );
83 t.destroy();
84 }
85 }
86 }
87 }
88 }
89
90
91 #region Monobehaviour
92
93 private void Update()
94 {
95 if( _tweens.Count == 0 )
96 return;
97
98 handleUpdateOfType( GoUpdateType.Update, Time.deltaTime );
99 }
100
101
102 private void LateUpdate()
103 {
104 if( _tweens.Count == 0 )
105 return;
106
107 handleUpdateOfType( GoUpdateType.LateUpdate, Time.deltaTime );
108 }
109
110
111 private void FixedUpdate()
112 {
113 if( _tweens.Count == 0 )
114 return;
115
116 handleUpdateOfType( GoUpdateType.FixedUpdate, Time.deltaTime );
117 }
118
119
120 private void OnApplicationQuit()
121 {
122 _instance = null;
123 Destroy( gameObject );
124 _applicationIsQuitting = true;
125 }
126
127 #endregion
128
129
130 /// <summary>
131 /// this only runs as needed and handles time scale independent Tweens
132 /// </summary>
133 private IEnumerator timeScaleIndependentUpdate()
134 {
135 _timeScaleIndependentUpdateIsRunning = true;
136 var time = Time.realtimeSinceStartup;
137
138 while( _tweens.Count > 0 )
139 {
140 var elapsed = Time.realtimeSinceStartup - time;
141 time = Time.realtimeSinceStartup;
142
143 // update tweens
144 handleUpdateOfType( GoUpdateType.TimeScaleIndependentUpdate, elapsed );
145
146 yield return null;
147 }
148
149 _timeScaleIndependentUpdateIsRunning = false;
150 }
151
152
153 /// <summary>
154 /// checks for duplicate properties. if one is found and the DuplicatePropertyRuleType is set to
155 /// DontAddCurrentProperty it will return true indicating that the tween should not be added.
156 /// this only checks tweens that are not part of an AbstractTweenCollection
157 /// </summary>
158 private static bool handleDuplicatePropertiesInTween( GoTween tween )
159 {
160 // first fetch all the current tweens with the same target object as this one
161 var allTweensWithTarget = tweensWithTarget( tween.target );
162
163 // store a list of all the properties in the tween
164 var allProperties = tween.allTweenProperties();
165
166 // TODO: perhaps only perform the check on running Tweens?
167
168 // loop through all the tweens with the same target
169 foreach( var tweenWithTarget in allTweensWithTarget )
170 {
171 // loop through all the properties in the tween and see if there are any dupes
172 foreach( var tweenProp in allProperties )
173 {
174 warn( "found duplicate TweenProperty {0} in tween {1}", tweenProp, tween );
175
176 // check for a matched property
177 if( tweenWithTarget.containsTweenProperty( tweenProp ) )
178 {
179 // handle the different duplicate property rules
180 if( duplicatePropertyRule == GoDuplicatePropertyRuleType.DontAddCurrentProperty )
181 {
182 return true;
183 }
184 else if( duplicatePropertyRule == GoDuplicatePropertyRuleType.RemoveRunningProperty )
185 {
186 // TODO: perhaps check if the Tween has any properties left and remove it if it doesnt?
187 tweenWithTarget.removeTweenProperty( tweenProp );
188 }
189
190 return false;
191 }
192 }
193 }
194
195 return false;
196 }
197
198
199 #region Logging
200
201 /// <summary>
202 /// logging should only occur in the editor so we use a conditional
203 /// </summary>
204 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
205 private static void log( object format, params object[] paramList )
206 {
207 if( format is string )
208 Debug.Log( string.Format( format as string, paramList ) );
209 else
210 Debug.Log( format );
211 }
212
213
214 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
215 public static void warn( object format, params object[] paramList )
216 {
217 if( logLevel == GoLogLevel.None || logLevel == GoLogLevel.Info )
218 return;
219
220 if( format is string )
221 Debug.LogWarning( string.Format( format as string, paramList ) );
222 else
223 Debug.LogWarning( format );
224 }
225
226
227 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
228 public static void error( object format, params object[] paramList )
229 {
230 if( logLevel == GoLogLevel.None || logLevel == GoLogLevel.Info || logLevel == GoLogLevel.Warn )
231 return;
232
233 if( format is string )
234 Debug.LogError( string.Format( format as string, paramList ) );
235 else
236 Debug.LogError( format );
237 }
238
239 #endregion
240
241
242 #region public API
243
244 /// <summary>
245 /// helper function that creates a "to" Tween and adds it to the pool
246 /// </summary>
247 public static GoTween to( object target, float duration, GoTweenConfig config )
248 {
249 config.setIsTo();
250 var tween = new GoTween( target, duration, config );
251 addTween( tween );
252
253 return tween;
254 }
255
256
257 /// <summary>
258 /// helper function that creates a "from" Tween and adds it to the pool
259 /// </summary>
260 public static GoTween from( object target, float duration, GoTweenConfig config )
261 {
262 config.setIsFrom();
263 var tween = new GoTween( target, duration, config );
264 addTween( tween );
265
266 return tween;
267 }
268
269
270 /// <summary>
271 /// adds an AbstractTween (Tween, TweenChain or TweenFlow) to the current list of running Tweens
272 /// </summary>
273 public static void addTween( AbstractGoTween tween )
274 {
275 // early out for invalid items
276 if( !tween.isValid() )
277 return;
278
279 // dont add the same tween twice
280 if( _tweens.Contains( tween ) )
281 return;
282
283 // check for dupes and handle them before adding the tween. we only need to check for Tweens
284 if( duplicatePropertyRule != GoDuplicatePropertyRuleType.None && tween is GoTween )
285 {
286 // if handleDuplicatePropertiesInTween returns true it indicates we should not add this tween
287 if( handleDuplicatePropertiesInTween( tween as GoTween ) )
288 return;
289
290 // if we became invalid after handling dupes dont add the tween
291 if( !tween.isValid() )
292 return;
293 }
294
295 _tweens.Add( tween );
296
297 // enable ourself if we are not enabled
298 if( !instance.enabled ) // purposely using the static instace property just once for initialization
299 _instance.enabled = true;
300
301 // if the Tween isn't paused and it is a "from" tween jump directly to the start position
302 if( tween is GoTween && ((GoTween)tween).isFrom && tween.state != GoTweenState.Paused )
303 tween.update( 0 );
304
305 // should we start up the time scale independent update?
306 if( !_instance._timeScaleIndependentUpdateIsRunning && tween.updateType == GoUpdateType.TimeScaleIndependentUpdate )
307 _instance.StartCoroutine( _instance.timeScaleIndependentUpdate() );
308
309 #if UNITY_EDITOR
310 _instance.gameObject.name = string.Format( "GoKit ({0} tweens)", _tweens.Count );
311 #endif
312 }
313
314
315 /// <summary>
316 /// removes the Tween returning true if it was removed or false if it was not found
317 /// </summary>
318 public static bool removeTween( AbstractGoTween tween )
319 {
320 if( _tweens.Contains( tween ) )
321 {
322 _tweens.Remove( tween );
323
324 #if UNITY_EDITOR
325 if( _instance != null && _tweens != null )
326 _instance.gameObject.name = string.Format( "GoKit ({0} tweens)", _tweens.Count );
327 #endif
328
329 if( _instance != null && _tweens.Count == 0 )
330 {
331 // disable ourself if we have no more tweens
332 _instance.enabled = false;
333 }
334
335 return true;
336 }
337
338 return false;
339 }
340
341
342 /// <summary>
343 /// returns a list of all Tweens, TweenChains and TweenFlows with the given id
344 /// </summary>
345 public static List<AbstractGoTween> tweensWithId( int id )
346 {
347 List<AbstractGoTween> list = null;
348
349 foreach( var tween in _tweens )
350 {
351 if( tween.id == id )
352 {
353 if( list == null )
354 list = new List<AbstractGoTween>();
355 list.Add( tween );
356 }
357 }
358
359 return list;
360 }
361
362
363 /// <summary>
364 /// returns a list of all Tweens with the given target. TweenChains and TweenFlows can optionally
365 /// be traversed and matching Tweens returned as well.
366 /// </summary>
367 public static List<GoTween> tweensWithTarget( object target, bool traverseCollections = false )
368 {
369 List<GoTween> list = new List<GoTween>();
370
371 foreach( var item in _tweens )
372 {
373 // we always check Tweens so handle them first
374 var tween = item as GoTween;
375 if( tween != null && tween.target == target )
376 list.Add( tween );
377
378 // optionally check TweenChains and TweenFlows. if tween is null we have a collection
379 if( traverseCollections && tween == null )
380 {
381 var tweenCollection = item as AbstractGoTweenCollection;
382 if( tweenCollection != null )
383 {
384 var tweensInCollection = tweenCollection.tweensWithTarget( target );
385 if( tweensInCollection.Count > 0 )
386 list.AddRange( tweensInCollection );
387 }
388 }
389 }
390
391 return list;
392 }
393
394
395 /// <summary>
396 /// kills all tweens with the given target by calling the destroy method on each one
397 /// </summary>
398 public static void killAllTweensWithTarget( object target )
399 {
400 foreach( var tween in tweensWithTarget( target, true ) )
401 tween.destroy();
402 }
403
404 #endregion
405
406 }
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 public class Go : MonoBehaviour
7 {
8 // defaults used for all tweens/properties that are not explicitly set
9 public static GoEaseType defaultEaseType = GoEaseType.Linear;
10 public static GoLoopType defaultLoopType = GoLoopType.RestartFromBeginning;
11 public static GoUpdateType defaultUpdateType = GoUpdateType.Update;
12
13 // defines what we should do in the event that a TweenProperty is added and an already existing tween has the same
14 // property and target
15 public static GoDuplicatePropertyRuleType duplicatePropertyRule = GoDuplicatePropertyRuleType.None;
16 public static GoLogLevel logLevel = GoLogLevel.Warn;
17
18 // validates that the target object still exists each tick of the tween. NOTE: it is recommended
19 // that you just properly remove your tweens before destroying any objects even though this might destroy them for you
20 public static bool validateTargetObjectsEachTick = true;
21
22 // Used to stop instances being created while the application is quitting
23 private static bool _applicationIsQuitting = false;
24
25 private static List<AbstractGoTween> _tweens = new List<AbstractGoTween>(); // contains Tweens, TweenChains and TweenFlows
26 private bool _timeScaleIndependentUpdateIsRunning;
27
28 // only one Go can exist
29 static Go _instance = null;
30 public static Go instance
31 {
32 get
33 {
34 // Don't allow new instances to be created when the application is quitting to avoid the GOKit object never being destroyed.
35 // These dangling instances can't be found with FindObjectOfType and so you'd get multiple instances in a scene.
36 if( !_instance && !_applicationIsQuitting )
37 {
38 // check if there is a GO instance already available in the scene graph
39 _instance = FindObjectOfType( typeof( Go ) ) as Go;
40
41 // possible Unity bug with FindObjectOfType workaround
42 //_instance = FindObjectOfType( typeof( Go ) ) ?? GameObject.Find( "GoKit" ).GetComponent<Go>() as Go;
43
44 // nope, create a new one
45 if( !_instance )
46 {
47 var obj = new GameObject( "GoKit" );
48 _instance = obj.AddComponent<Go>();
49 DontDestroyOnLoad( obj );
50 }
51 }
52
53 return _instance;
54 }
55 }
56
57
58 /// <summary>
59 /// loops through all the Tweens and updates any that are of updateType. If any Tweens are complete
60 /// (the update call will return true) they are removed.
61 /// </summary>
62 private void handleUpdateOfType( GoUpdateType updateType, float deltaTime )
63 {
64 // loop backwards so we can remove completed tweens
65 for( var i = _tweens.Count - 1; i >= 0; --i )
66 {
67 var t = _tweens[i];
68
69 if( t.state == GoTweenState.Destroyed )
70 {
71 // destroy method has been called
72 removeTween( t );
73 }
74 else
75 {
76 // only process tweens with our update type that are running
77 if( t.updateType == updateType && t.state == GoTweenState.Running && t.update( deltaTime * t.timeScale ) )
78 {
79 // tween is complete if we get here. if destroyed or set to auto remove kill it
80 if( t.state == GoTweenState.Destroyed || t.autoRemoveOnComplete )
81 {
82 removeTween( t );
83 t.destroy();
84 }
85 }
86 }
87 }
88 }
89
90
91 #region Monobehaviour
92
93 private void Update()
94 {
95 if( _tweens.Count == 0 )
96 return;
97
98 handleUpdateOfType( GoUpdateType.Update, Time.deltaTime );
99 }
100
101
102 private void LateUpdate()
103 {
104 if( _tweens.Count == 0 )
105 return;
106
107 handleUpdateOfType( GoUpdateType.LateUpdate, Time.deltaTime );
108 }
109
110
111 private void FixedUpdate()
112 {
113 if( _tweens.Count == 0 )
114 return;
115
116 handleUpdateOfType( GoUpdateType.FixedUpdate, Time.deltaTime );
117 }
118
119
120 private void OnApplicationQuit()
121 {
122 _instance = null;
123 Destroy( gameObject );
124 _applicationIsQuitting = true;
125 }
126
127 #endregion
128
129
130 /// <summary>
131 /// this only runs as needed and handles time scale independent Tweens
132 /// </summary>
133 private IEnumerator timeScaleIndependentUpdate()
134 {
135 _timeScaleIndependentUpdateIsRunning = true;
136 var time = Time.realtimeSinceStartup;
137
138 while( _tweens.Count > 0 )
139 {
140 var elapsed = Time.realtimeSinceStartup - time;
141 time = Time.realtimeSinceStartup;
142
143 // update tweens
144 handleUpdateOfType( GoUpdateType.TimeScaleIndependentUpdate, elapsed );
145
146 yield return null;
147 }
148
149 _timeScaleIndependentUpdateIsRunning = false;
150 }
151
152
153 /// <summary>
154 /// checks for duplicate properties. if one is found and the DuplicatePropertyRuleType is set to
155 /// DontAddCurrentProperty it will return true indicating that the tween should not be added.
156 /// this only checks tweens that are not part of an AbstractTweenCollection
157 /// </summary>
158 private static bool handleDuplicatePropertiesInTween( GoTween tween )
159 {
160 // first fetch all the current tweens with the same target object as this one
161 var allTweensWithTarget = tweensWithTarget( tween.target );
162
163 // store a list of all the properties in the tween
164 var allProperties = tween.allTweenProperties();
165
166 // TODO: perhaps only perform the check on running Tweens?
167
168 // loop through all the tweens with the same target
169 foreach( var tweenWithTarget in allTweensWithTarget )
170 {
171 // loop through all the properties in the tween and see if there are any dupes
172 foreach( var tweenProp in allProperties )
173 {
174 warn( "found duplicate TweenProperty {0} in tween {1}", tweenProp, tween );
175
176 // check for a matched property
177 if( tweenWithTarget.containsTweenProperty( tweenProp ) )
178 {
179 // handle the different duplicate property rules
180 if( duplicatePropertyRule == GoDuplicatePropertyRuleType.DontAddCurrentProperty )
181 {
182 return true;
183 }
184 else if( duplicatePropertyRule == GoDuplicatePropertyRuleType.RemoveRunningProperty )
185 {
186 // TODO: perhaps check if the Tween has any properties left and remove it if it doesnt?
187 tweenWithTarget.removeTweenProperty( tweenProp );
188 }
189
190 return false;
191 }
192 }
193 }
194
195 return false;
196 }
197
198
199 #region Logging
200
201 /// <summary>
202 /// logging should only occur in the editor so we use a conditional
203 /// </summary>
204 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
205 private static void log( object format, params object[] paramList )
206 {
207 if( format is string )
208 Debug.Log( string.Format( format as string, paramList ) );
209 else
210 Debug.Log( format );
211 }
212
213
214 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
215 public static void warn( object format, params object[] paramList )
216 {
217 if( logLevel == GoLogLevel.None || logLevel == GoLogLevel.Info )
218 return;
219
220 if( format is string )
221 Debug.LogWarning( string.Format( format as string, paramList ) );
222 else
223 Debug.LogWarning( format );
224 }
225
226
227 [System.Diagnostics.Conditional( "UNITY_EDITOR" )]
228 public static void error( object format, params object[] paramList )
229 {
230 if( logLevel == GoLogLevel.None || logLevel == GoLogLevel.Info || logLevel == GoLogLevel.Warn )
231 return;
232
233 if( format is string )
234 Debug.LogError( string.Format( format as string, paramList ) );
235 else
236 Debug.LogError( format );
237 }
238
239 #endregion
240
241
242 #region public API
243
244 /// <summary>
245 /// helper function that creates a "to" Tween and adds it to the pool
246 /// </summary>
247 public static GoTween to( object target, float duration, GoTweenConfig config )
248 {
249 config.setIsTo();
250 var tween = new GoTween( target, duration, config );
251 addTween( tween );
252
253 return tween;
254 }
255
256
257 /// <summary>
258 /// helper function that creates a "from" Tween and adds it to the pool
259 /// </summary>
260 public static GoTween from( object target, float duration, GoTweenConfig config )
261 {
262 config.setIsFrom();
263 var tween = new GoTween( target, duration, config );
264 addTween( tween );
265
266 return tween;
267 }
268
269
270 /// <summary>
271 /// adds an AbstractTween (Tween, TweenChain or TweenFlow) to the current list of running Tweens
272 /// </summary>
273 public static void addTween( AbstractGoTween tween )
274 {
275 // early out for invalid items
276 if( !tween.isValid() )
277 return;
278
279 // dont add the same tween twice
280 if( _tweens.Contains( tween ) )
281 return;
282
283 // check for dupes and handle them before adding the tween. we only need to check for Tweens
284 if( duplicatePropertyRule != GoDuplicatePropertyRuleType.None && tween is GoTween )
285 {
286 // if handleDuplicatePropertiesInTween returns true it indicates we should not add this tween
287 if( handleDuplicatePropertiesInTween( tween as GoTween ) )
288 return;
289
290 // if we became invalid after handling dupes dont add the tween
291 if( !tween.isValid() )
292 return;
293 }
294
295 _tweens.Add( tween );
296
297 // enable ourself if we are not enabled
298 if( !instance.enabled ) // purposely using the static instace property just once for initialization
299 _instance.enabled = true;
300
301 // if the Tween isn't paused and it is a "from" tween jump directly to the start position
302 if( tween is GoTween && ((GoTween)tween).isFrom && tween.state != GoTweenState.Paused )
303 tween.update( 0 );
304
305 // should we start up the time scale independent update?
306 if( !_instance._timeScaleIndependentUpdateIsRunning && tween.updateType == GoUpdateType.TimeScaleIndependentUpdate )
307 _instance.StartCoroutine( _instance.timeScaleIndependentUpdate() );
308
309 #if UNITY_EDITOR
310 _instance.gameObject.name = string.Format( "GoKit ({0} tweens)", _tweens.Count );
311 #endif
312 }
313
314
315 /// <summary>
316 /// removes the Tween returning true if it was removed or false if it was not found
317 /// </summary>
318 public static bool removeTween( AbstractGoTween tween )
319 {
320 if( _tweens.Contains( tween ) )
321 {
322 _tweens.Remove( tween );
323
324 #if UNITY_EDITOR
325 if( _instance != null && _tweens != null )
326 _instance.gameObject.name = string.Format( "GoKit ({0} tweens)", _tweens.Count );
327 #endif
328
329 if( _instance != null && _tweens.Count == 0 )
330 {
331 // disable ourself if we have no more tweens
332 _instance.enabled = false;
333 }
334
335 return true;
336 }
337
338 return false;
339 }
340
341
342 /// <summary>
343 /// returns a list of all Tweens, TweenChains and TweenFlows with the given id
344 /// </summary>
345 public static List<AbstractGoTween> tweensWithId( int id )
346 {
347 List<AbstractGoTween> list = null;
348
349 foreach( var tween in _tweens )
350 {
351 if( tween.id == id )
352 {
353 if( list == null )
354 list = new List<AbstractGoTween>();
355 list.Add( tween );
356 }
357 }
358
359 return list;
360 }
361
362
363 /// <summary>
364 /// returns a list of all Tweens with the given target. TweenChains and TweenFlows can optionally
365 /// be traversed and matching Tweens returned as well.
366 /// </summary>
367 public static List<GoTween> tweensWithTarget( object target, bool traverseCollections = false )
368 {
369 List<GoTween> list = new List<GoTween>();
370
371 foreach( var item in _tweens )
372 {
373 // we always check Tweens so handle them first
374 var tween = item as GoTween;
375 if( tween != null && tween.target == target )
376 list.Add( tween );
377
378 // optionally check TweenChains and TweenFlows. if tween is null we have a collection
379 if( traverseCollections && tween == null )
380 {
381 var tweenCollection = item as AbstractGoTweenCollection;
382 if( tweenCollection != null )
383 {
384 var tweensInCollection = tweenCollection.tweensWithTarget( target );
385 if( tweensInCollection.Count > 0 )
386 list.AddRange( tweensInCollection );
387 }
388 }
389 }
390
391 return list;
392 }
393
394
395 /// <summary>
396 /// kills all tweens with the given target by calling the destroy method on each one
397 /// </summary>
398 public static void killAllTweensWithTarget( object target )
399 {
400 foreach( var tween in tweensWithTarget( target, true ) )
401 tween.destroy();
402 }
403
404 #endregion
405
406 }